package com.evil.application.service.impl;

import com.evil.application.api.RemoteButtonActionService;
import com.evil.application.mapper.ApplicationButtonMapper;
import com.evil.application.mapper.ApplicationInfoMapper;
import com.evil.application.mapper.ApplicationOrderMapper;
import com.evil.application.pojo.entity.ApplicationButton;
import com.evil.application.pojo.entity.ApplicationInfo;
import com.evil.application.pojo.entity.ApplicationOrder;
import com.evil.application.service.ApplicationJudgeService;
import com.evil.application.service.ApplicationPermissionService;
import com.evil.application.service.ApplicationRobotRuleService;
import com.evil.application.service.RobotActionService;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.button.ButtonActionBatchReqDTO;
import com.evil.common.application.dto.button.ButtonActionReqDTO;
import com.evil.common.application.dto.judge.JudgeOr;
import com.evil.common.application.dto.judge.JudgeSourceDTO;
import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.dto.permission.app.AppPermissionSourceDTO;
import com.evil.common.application.dto.robot.RobotRuleDTO;
import com.evil.common.application.dto.robot.action.RobotActionReqDTO;
import com.evil.common.application.dto.robot.rule.RobotRuleSourceDTO;
import com.evil.common.application.enums.ApplicationSourceTypeEnum;
import com.evil.common.application.enums.button.TriggerActionEnum;
import com.evil.common.application.enums.judge.JudgeSourceTypeEnum;
import com.evil.common.application.enums.permission.PermissionStatusEnum;
import com.evil.common.application.enums.robot.RobotRuleSourceTypeEnum;
import com.evil.common.application.enums.robot.RobotSourceTypeEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 自定义按钮执行
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ButtonActionServiceImpl implements RemoteButtonActionService {

    private final LoginUtil loginUtil;

    private final ApplicationButtonMapper applicationButtonMapper;

    private final ApplicationOrderMapper applicationOrderMapper;

    private final ApplicationInfoMapper applicationInfoMapper;

    private final RobotActionService robotActionService;

    private final ApplicationRobotRuleService applicationRobotRuleService;

    private final ApplicationJudgeService applicationJudgeService;

    private final ApplicationPermissionService applicationPermissionService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public List<ControlDataDTO> buttonAction(ButtonActionReqDTO buttonActionReqDTO) {
        ApplicationButton button = applicationButtonMapper.findById(buttonActionReqDTO.getButtonId());
        ApplicationOrder order = applicationOrderMapper.findById(buttonActionReqDTO.getOrderId());
        ApplicationInfo applicationInfo = applicationInfoMapper.findById(order.getApplicationId());

        // 检查企业
        loginUtil.checkEnterpriseId(button.getEnterpriseId());

        // 检验密码
        this.checkPermission(button, buttonActionReqDTO.getPassword());
        if (TriggerActionEnum.JUMP_LINK.getId() == button.getTriggerAction()) {
            return new ArrayList<>();
        }
        TriggerActionEnum triggerActionEnum = TriggerActionEnum.isExistById(button.getTriggerAction());
        if (Objects.isNull(triggerActionEnum.getRobotTriggerTypeEnum())) {
            throw TriggerActionEnum.getBusinessException();
        }

        RobotActionReqDTO robotActionReqDTO = new RobotActionReqDTO();
        robotActionReqDTO.setEnterpriseId(order.getEnterpriseId());
        robotActionReqDTO.setOrderId(buttonActionReqDTO.getOrderId());
        robotActionReqDTO.setApplicationId(order.getApplicationId());
        robotActionReqDTO.setApplicationKey(applicationInfo.getApplicationKey());
        robotActionReqDTO.setTriggerType(triggerActionEnum.getRobotTriggerTypeEnum().getId());
        robotActionReqDTO.setTriggerId(button.getButtonId());
        robotActionReqDTO.setTriggerName(button.getButtonName());
        robotActionReqDTO.setRobotSourceTypeEnum(RobotSourceTypeEnum.BUTTON);
        robotActionReqDTO.setTargetAppId(button.getTargetApplicationId());
        robotActionReqDTO.setSaveNow(true);
        robotActionReqDTO.setSync(SwitchEnum.YES.getId());

        // 获取按钮规则
        if (TriggerActionEnum.hasRule(button.getTriggerAction())) {
            robotActionReqDTO.setRobotRules(applicationRobotRuleService.findBySource(
                    new RobotRuleSourceDTO(RobotRuleSourceTypeEnum.CUSTOM_BUTTON_RULE, button.getButtonId())));
        }
        // 获取筛选条件
        if (TriggerActionEnum.hasJudge(button.getTriggerAction())) {
            robotActionReqDTO.setJudgeOrs(applicationJudgeService.findDTOBySource(
                    new JudgeSourceDTO(JudgeSourceTypeEnum.APPLICATION_BUTTON_FILTER_CONDITION, button.getButtonId())));
        }

        return robotActionService.robotActionBeforeLog(robotActionReqDTO);
    }

    /**
     * 按钮动作-批量（编辑数据按钮使用）
     *
     * @param buttonActionBatchReqDTO buttonActionBatchReqDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public List<List<ControlDataDTO>> buttonAction(ButtonActionBatchReqDTO buttonActionBatchReqDTO) {
        ApplicationButton button = applicationButtonMapper.findById(buttonActionBatchReqDTO.getButtonId());
        LinkedHashSet<Long> orderIds = new LinkedHashSet<>(buttonActionBatchReqDTO.getOrderIds());
        List<ApplicationOrder> orders = applicationOrderMapper.findByIds(orderIds, true);
        Map<Long, Long> orderAppIdMap = StreamUtil.toMapKV(orders, ApplicationOrder::getOrderId, ApplicationOrder::getApplicationId);
        if (orderAppIdMap.size() != orderIds.size()) {
            throw new BusinessException(RCodeEnum.APPLICATION_ORDER_NOT_EXIST);
        }
        Set<Long> appIds = new HashSet<>(orderAppIdMap.values());
        List<ApplicationInfo> apps = applicationInfoMapper.findByIds(appIds, true);
        if (appIds.size() != apps.size()) {
            throw new BusinessException(RCodeEnum.APPLICATION_INFO_NOT_EXIST);
        }

        // 检查企业
        apps.forEach(a -> loginUtil.checkEnterpriseId(a.getEnterpriseId()));

        Map<Long, String> applicationKeyMap = StreamUtil.toMapKV(apps, ApplicationInfo::getApplicationId, ApplicationInfo::getApplicationKey);
        Map<Long, String> orderAppKeyMap = StreamUtil.transMapV(orderAppIdMap, applicationKeyMap::get);

        // 检验密码
        this.checkPermission(button, buttonActionBatchReqDTO.getPassword());
        TriggerActionEnum triggerActionEnum = TriggerActionEnum.isExistById(button.getTriggerAction());
        if (Objects.isNull(triggerActionEnum.getRobotTriggerTypeEnum())) {
            throw TriggerActionEnum.getBusinessException();
        }

        // 获取按钮规则
        List<RobotRuleDTO> robotRules = applicationRobotRuleService.findBySource(
                new RobotRuleSourceDTO(RobotRuleSourceTypeEnum.CUSTOM_BUTTON_RULE, button.getButtonId()));
        // 获取筛选条件
        List<JudgeOr> judgeOrs = applicationJudgeService.findDTOBySource(
                new JudgeSourceDTO(JudgeSourceTypeEnum.APPLICATION_BUTTON_FILTER_CONDITION, button.getButtonId()));

        return orderIds.stream().map(orderId -> {
            RobotActionReqDTO robotActionReqDTO = new RobotActionReqDTO();
            robotActionReqDTO.setOrderId(orderId);
            robotActionReqDTO.setTargetAppId(button.getTargetApplicationId());
            robotActionReqDTO.setRobotRules(robotRules);
            robotActionReqDTO.setJudgeOrs(judgeOrs);
            robotActionReqDTO.setTriggerType(triggerActionEnum.getRobotTriggerTypeEnum().getId());
            robotActionReqDTO.setSaveNow(true);
            robotActionReqDTO.setTriggerId(button.getButtonId());
            robotActionReqDTO.setTriggerName(button.getButtonName());
            robotActionReqDTO.setRobotSourceTypeEnum(RobotSourceTypeEnum.BUTTON);
            robotActionReqDTO.setApplicationKey(orderAppKeyMap.get(orderId));

            return robotActionService.robotActionBeforeLog(robotActionReqDTO);
        }).collect(Collectors.toList());
    }

    /**
     * 检查权限
     *
     * @param button   button
     * @param password password
     */
    private void checkPermission(ApplicationButton button, String password) {
        // 指定权限
        if (PermissionStatusEnum.ASSIGN.getId() == button.getPermissionStatus()) {
            AppPermissionSourceDTO appPermissionReqDTO = new AppPermissionSourceDTO(ApplicationSourceTypeEnum.APPLICATION_BUTTON, button.getButtonId());
            // 开启密码校验
            if (SwitchEnum.isOpen(button.getPasswordStatus())) {
                applicationPermissionService.checkPassword(appPermissionReqDTO, password);
            }
            // 关闭密码校验
            else {
                if (!applicationPermissionService.loginUserHasPermission(appPermissionReqDTO, true)) {
                    throw new BusinessException(RCodeEnum.ERROR_UNAUTHORIZED);
                }
            }
        }
        // 全体权限
        else {
            // 开启密码校验
            if (SwitchEnum.isOpen(button.getPasswordStatus())) {
                if (!Objects.equals(button.getPassword(), password)) {
                    throw new BusinessException(RCodeEnum.PASSWORD_ERROR);
                }
            }
        }
    }
}
